#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__


#include"Logger.hpp"
#include"InetAddr.hpp"
#include<iostream>
#include <sys/types.h>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<memory>



enum 
{
    OK,
    CREAT_ERR,
    BINF_ERR,
    LISTEN_ERR,
}
static int gbacklog=16;
static const int gsockfd=-1;
//创建Socket模板，模板方法模式
class Socket 
{
public:
//一部分由子类去实现
    virtual ~Socket() {}
    //创建 绑定 听 接收
    virtual void CreatSocketOrDie()=0;
    virtual void BindSocketOrDie()=0;
    virtual void ListenSocketOrDie()=0;
    virtual std::shared_ptr<Socket> Accept(InetAddr*clientaddr)=0;
    virtual int SockFd()=0;
    virtual int Close()=0;
    virtual ssize_t Recv(std::string *out)=0;
    virtual ssize_t Send(std::string &in)=0;

public:
    void BuildSocketMetod()
    {
        CreatSocketOrDie();
        BindSocketOrDie();
        ListenSocketOrDie();//对于Udp来讲这个是空的
    }
    // void BuildListenSocketMetod()
    // {
    //     //创建 绑定 听 Init;
    //     CreatSocketOrDie();
    //     BindSocketOrDie();
    //     ListenSocketOrDie();
    // }
    // void BuildUdpSocketMetod()
    // {
    //     CreatSocketOrDie();
    //     BindSocketOrDie();
    // }

}

//TcpSocket
class TcpSocket:public Socket  //具体实现类
{
public:
    TcpSocket():_sockfd(gsockfd)
    {}//构造listen套接字
    TcpSocket(int sockfd):_sockfd(sockfd)
    {}//有参数的对普通套接字做封装
    void CreatSocketOrDie() override
    {
        _sockfd_=socket(AF_INET,SOCK_STREAM,0);//
        if(sockfd_<0)
        {
           LOG(LogLevel::FATAL)<<"creat sockfd error!!!";
           exit(CREAT_ERR);
        }
    }
    void BindSocketOrDie() override
    {
        InetAddr local(port);
        if(bind(_sockfd,local.Addr(),local.Length())!=0)
        {
            LOG(LogLevel::FATAL)<<"bind socket error";
            exit(BINF_ERR);
        }
        
    }
    void ListenSocketOrDie() override
    {
        if(listen(_sockfd,backlog)!=0)
        {
             LOG(LogLevel::FATAL)<<"Listen socket error";
            exit(LISTEN_ERR);

        }
    }
    //int Accept(InetAddr*clientaddr) override//输出型参数，一旦获取到客户端地址，就存储到addr中带出来
    std::shared_ptr<Socket>Accept(InetAddr* clientaddr)=0;//这样服务器上的所有套接字都可以利用这里的方法
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        int fd=accept(_sockfd,(struct sockaddr*)&peer,&len);
        if(fd<0)
        {
            LOG(LogLevel::WARNING)<<"accept error";
            return ;
        }
        clientaddr->Init(peer);
        return std::make_shared<TcpSocket>();
        //return fd;

    }
    int SockFd() override
    {
        return _sockfd;
    }
    int Close() override
    {
        if(_sockfd>=0)
        close(_sockfd);
    }
    ssize_t Recv(std::string *out) override
    {
        //具体的接收数据的实现
        //只读一次
        char buffer[1024];
        ssize_t n=recv(_sockfd,buffer,sizeof(buffer)-1,0);
        if(n>0)
        {
            buffer[n]=0;
            *out+=buffer;
        }
        return n;
    }
    ssize_t Send(std::string &in) override
    {
        //具体的发送数据的实现
      return write(_sockfd,in.c_str(),in.size(),0);//也有问题其实
    }
    ~TcpSocket()
    {}
private:
    int _sockfd;
}
















#endif